#include <stdio.h>
#include <string.h>
#include <signal.h>
#include <fibthread.h>
#include <unistd.h>
#include <errno.h>

void * foo(void *arg);
void * bar(void *arg);
void * sigint(void *arg);
void sigint_handler(int signo);

/*
 * The example will be as follow foo and bar will be blocking all of the signals.
 * Foo will unblock SIGQUIT and SIGHUP. And sigint thread will be handling sigints but not
 * sigquits. It will be blocking SIGQUIT and not SIGINT. The foo will send SIGINT
 * and SIGQUIT to sigint thread. It will handle the SIGINT but will raise only SIGQUIT
 * without doing anything. The purpose here is to see if the fibthread_kill works and
 * if the signals send to specific threads, effects the other threads !
 *
 * At the end the end the sigint will raise the SIGHUP to finish the process !
 *
 * */

int main(int argc, char *argv[]){

	sigset_t th_sigmask;
	int result, error;
	fibthread_t tfoo, tbar, tsig;
	fibthread_attr_t tattr;

	/* Now start waiting for threads to finish */
	if ((error = fibthread_attr_init(&tattr)) != 0)
		fprintf(stderr, "Failed to create attribute object: %s\n",strerror(error));
	else if ((error = fibthread_attr_setdetachstate(&tattr,FIBTHREAD_CREATE_DETACHED)) != 0)
		fprintf(stderr, "Failed to set attribute state to detached: %s\n",
						  strerror(error));

	/* First we block all of the signals so
	 * the created children inherits them */


	sigfillset(&th_sigmask);
	if((result = fibthread_sigmask(SIG_SETMASK, &th_sigmask, NULL)) != 0)
		fprintf(stderr, "fibthread_sigmask : %s \n",strerror(result));

	/* Now create the threads */
	if((result = fibthread_create(&tsig, &tattr, sigint, NULL)) != 0)
					fprintf(stderr, "fibthread_create : %s \n",strerror(result));
	if((result = fibthread_create(&tfoo, &tattr, foo, (void *)&tsig)) != 0)
			fprintf(stderr, "fibthread_create : %s \n",strerror(result));
	if((result = fibthread_create(&tbar, &tattr, bar, NULL)) != 0)
				fprintf(stderr, "fibthread_create : %s \n",strerror(result));


	printf("Main thread is exiting ... \n");
	fibthread_exit(0);

	return 0;
}


void * foo(void *arg){
	int result;
	fibthread_t *sigt;
	sigset_t sigquit_set;

	sigt = (fibthread_t *)arg;

	/* Open the SIGQUIT so we can end up the process */
	sigemptyset(&sigquit_set);
	sigaddset(&sigquit_set,SIGHUP);
	sigaddset(&sigquit_set,SIGQUIT);

	if((result = fibthread_sigmask(SIG_UNBLOCK, &sigquit_set, NULL)) != 0)
		fprintf(stderr, "fibthread_sigmask-sigquit : %s \n",strerror(result));

	while(1){
		printf("In foo ... \n");
		fibthread_kill(*sigt, SIGINT);
		fibthread_kill(*sigt, SIGQUIT);
		sleep(3);
		fibthread_yield();
	}
	return NULL;
}

void * bar(void *arg){

	while(1){
		printf("In bar ... \n");
		sleep(3);
		fibthread_yield();
	}

	return NULL;
}

void * sigint(void *arg){
	int result, i = 0;
	sigset_t sigint_set;
	struct sigaction siga;

	/* Set the sigaction here */
	siga.sa_handler = sigint_handler;
	siga.sa_flags = 0;
	sigfillset(&siga.sa_mask);

	if(sigaction(SIGINT, &siga, NULL) < 0)
		fprintf(stderr, "sigaction : %s \n",strerror(errno));

	sigemptyset(&sigint_set);
	sigaddset(&sigint_set,SIGINT);

	if((result = fibthread_sigmask(SIG_UNBLOCK, &sigint_set, NULL)) != 0)
			fprintf(stderr, "fibthread_sigmask-sigint : %s \n",strerror(result));

	for(i = 0; i < 5; i++){
		printf("In sigint ... \n");
		sleep(3);
		fibthread_yield();
	}

	printf("The end of sigint, you all will die ... \n");
	// QUIT the process !

	kill(getpid(), SIGHUP);

	return NULL;
}

void sigint_handler(int signo){

	printf("Received SIGINT \n");

}
